A static analysis tool for detecting code patterns that make Java applications vulnerable to CVE-2022-42889 (Text4Shell) and CVE-2025-46295 - Remote Code Execution vulnerabilities in Apache Commons Text.
Apache Commons Text versions 1.5 through 1.9 contain a critical vulnerability in the string interpolation feature. The StringSubstitutor class, when configured with default interpolators, enables dangerous lookups that can be exploited for:
- Remote Code Execution via
${script:javascript:...}payloads - Server-Side Request Forgery (SSRF) via
${url:...}payloads - DNS Exfiltration via
${dns:...}payloads
| CVE | CVSS Score | Affected Versions | Fixed Version |
|---|---|---|---|
| CVE-2022-42889 | 9.8 (Critical) | 1.5 - 1.9 | 1.10.0+ |
| CVE-2025-46295 | Critical | 1.5 - 1.9 | 1.10.0+ |
For successful exploitation, all four vectors must be present:
| Vector | Description | Example |
|---|---|---|
| 1 | Vulnerable Dependency | commons-text:1.9 in pom.xml |
| 2 | Dangerous Interpolator | StringSubstitutor.createInterpolator() |
| 3 | Untrusted Input | User input passed to replace() |
| 4 | No Input Sanitization | Missing ${...} pattern filtering |
No installation required. The scanner is a standalone Python 3 script with no external dependencies.
# Clone or download
git clone <repository-url>
cd commons-text-scanner
# Verify Python 3 is available
python --version # or python3 --versionpython commons_text_antipattern_scanner.py /path/to/java/project| Option | Description |
|---|---|
directory |
Directory to scan (required) |
-f, --format |
Output format: text (default) or json |
-o, --output |
Write output to file instead of stdout |
--no-recursive |
Only scan the specified directory, not subdirectories |
-V, --vector |
Scan for specific vector only (1, 2, 3, or 4) |
--severity |
Minimum severity to report: CRITICAL, HIGH, MEDIUM, LOW, INFO |
# Scan project and save report
python commons_text_antipattern_scanner.py ./my-java-app -o report.txt
# JSON output for CI/CD integration
python commons_text_antipattern_scanner.py ./my-java-app --format json -o results.json
# Check only for vulnerable dependency versions (Vector 1)
python commons_text_antipattern_scanner.py ./my-java-app --vector 1
# Show only CRITICAL and HIGH severity findings
python commons_text_antipattern_scanner.py ./my-java-app --severity HIGH
# Scan single directory without recursion
python commons_text_antipattern_scanner.py ./my-java-app/src/main/java --no-recursive================================================================================
APACHE COMMONS TEXT ANTI-PATTERN SCAN RESULTS
CVE-2022-42889 (Text4Shell) / CVE-2025-46295
================================================================================
EXPLOITATION VECTORS REQUIRED:
----------------------------------------
Vector 1: Vulnerable Dependency (Commons Text 1.5-1.9)
Vector 2: Dangerous Interpolator (createInterpolator/script/dns/url)
Vector 3: Untrusted Input (user data to replace())
Vector 4: No Input Sanitization (missing ${...} filtering)
EXPLOITABILITY ANALYSIS:
----------------------------------------
Vector 1: [FOUND] (2 findings)
Vector 2: [FOUND] (3 findings)
Vector 3: [FOUND] (1 findings)
Vector 4: [NOT FOUND] (0 findings)
Missing vectors: 4
Exploitation requires all 4 vectors to be present.
{
"summary": {
"total_findings": 6,
"files_affected": 3,
"by_severity": {"CRITICAL": 2, "HIGH": 3, "MEDIUM": 1},
"by_vector": {"1": 2, "2": 3, "3": 1, "4": 0}
},
"exploitability_analysis": {
"all_vectors_present": false,
"vectors_found": {"1": true, "2": true, "3": true, "4": false},
"missing_vectors": [4],
"assessment": "Potentially exploitable - Missing vectors: [4]"
},
"findings": [...]
}| Code | Meaning |
|---|---|
| 0 | No critical/high findings |
| 1 | Critical or high severity findings detected |
| 2 | All exploitation vectors present - likely exploitable |
Scans pom.xml and build.gradle files for:
- Apache Commons Text versions 1.5, 1.6, 1.7, 1.8, 1.9
- Maven and Gradle dependency declarations
Detects usage of:
StringSubstitutor.createInterpolator()ScriptStringLookup(enables RCE)DnsStringLookup(enables DNS exfiltration)UrlStringLookup(enables SSRF)StringLookupFactoryusage
Identifies data flow patterns where user input reaches replace():
- HTTP request parameters (
@RequestParam,@PathVariable,@RequestBody) - Servlet request handling
- Controller methods
- File content from uploads
- Database query results
- Message queue listeners
Detects absence of:
- Pattern validation for
${...}syntax - Input sanitization/escaping
- Whitelist filtering
Upgrade to Apache Commons Text 1.10.0 or later:
Maven (pom.xml):
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.12.0</version>
</dependency>Gradle (build.gradle):
implementation 'org.apache.commons:commons-text:1.12.0'Reject input containing interpolation syntax:
private static final Pattern DANGEROUS_PATTERN = Pattern.compile("\\$\\{[^}]+\\}");
public String safeProcess(String input) {
if (DANGEROUS_PATTERN.matcher(input).find()) {
throw new SecurityException("Invalid input: interpolation syntax not allowed");
}
return substitutor.replace(input);
}Use a custom StringSubstitutor without dangerous lookups:
// Safe: Only use environment and system property lookups
Map<String, StringLookup> lookups = new HashMap<>();
lookups.put("env", StringLookupFactory.INSTANCE.environmentVariableStringLookup());
lookups.put("sys", StringLookupFactory.INSTANCE.systemPropertyStringLookup());
StringLookup safeLookup = StringLookupFactory.INSTANCE.interpolatorStringLookup(lookups, null, false);
StringSubstitutor substitutor = new StringSubstitutor(safeLookup);- name: Scan for Commons Text vulnerabilities
run: |
python commons_text_antipattern_scanner.py ./src --format json -o scan-results.json
if [ $? -eq 2 ]; then
echo "CRITICAL: All exploitation vectors detected!"
exit 1
fistage('Security Scan') {
steps {
sh 'python commons_text_antipattern_scanner.py ./src -o commons-text-report.txt'
}
post {
always {
archiveArtifacts artifacts: 'commons-text-report.txt'
}
}
}- Static analysis only - does not execute code or trace runtime data flow
- May produce false positives for variable names matching patterns
- Cannot detect vulnerabilities in compiled JAR dependencies
- Multiline pattern matching is heuristic-based
| File Type | Extensions/Names |
|---|---|
| Java source | .java |
| Maven | pom.xml |
| Gradle | build.gradle, build.gradle.kts |
| XML config | .xml |
GNU General Public License v3.0 (GPL-3.0)
Copyright (C) 2025 Garland Glessner <gglessner@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Garland Glessner (gglessner@gmail.com)